# coding:utf-8

import itertools
import os


class ZuhePara:

    def dataInfo(self, list):
        '''
        :param list: 元素为字典的列表，如：[{'paraName': 'identityCode', 'type': 'String', 'notNone': 1必填，0非必填, 'value': [1, 2, 3]},...]
        :return: 必填dict，非必填dict，非必填的key组成的list
        '''
        dict_1 = {}
        dict_0 = {}
        list_0 = []
        for parame in list:
            if parame['notNone'] == 1:
                dict_1[parame['paraName']] = parame['value']
            else:
                dict_0[parame['paraName']] = parame['value']
                list_0.append(parame['paraName'])
        print('必填dict_1', dict_1)
        print('非必填dict_0', dict_0)
        print('非必填项的key组成的list_0', list_0)
        return dict_1, dict_0, list_0

    def feiData(self, list_0, dict_0):
        '''

        :param list_0: 非必填参数名组成的list，如：['channelParam', 'isNeedOcrText', 'isNeedOcrImage', 'isNeedVideo']
        :param dict_0: 非必填字段字典
        :return: 非必填项的排列组合 list
        '''
        if len(list_0) == 0:
            return []
        # 为空的参数个数可能为0到len(list_0)，假设非逼传参数有4个
        # 参数为空个数    0   1   2   3   4
        #    几种情况    1  C41 C42 C43 C44
        pailie_list = []
        dict_list = []
        # 4个参数全为空时
        pailie_list.append(tuple(list_0))
        # C41--C44
        for i in range(1, len(list_0) + 1):
            pailie_list.extend(list(itertools.combinations(iterable=list_0, r=i)))

        print('非必填排列组合总数:', len(pailie_list))
        # print('非必填字段的key排列组合pailie_list：', pailie_list)
        for i in pailie_list:
            new_dict_0 = dict_0.copy()
            for j in i:
                new_dict_0[j] = ''
            dict_list.append(new_dict_0)
        # 注意这里全部为空和全部不为空的key组合都是一样的且默认显示的是全为空的格式，所以把其中一个改为不全为空即可
        dict_list[0] = dict_0
        print('非必填字段排列组合dict_list', dict_list)
        return dict_list

    def biData(self, dict_1):
        '''
        考虑到必填字段有时候会有多个值选择，如：code：第一种情况，1；第二种情况，2
        :param dict_1: 必填参数字典，如：{'identityCode': [1, 2, 3], 'channel': ['A', 'B', 'C'], 'extra': ['a', 'b', 'c']}
        :return: 必填字段的排列组合 list
        '''

        # 定义一个列表，元素为每个必填参数可选值的列表
        para_list = []
        # 排列组合后的列表dict = {'Name': 'Runoob', 'Age': 7}
        pai_list = []
        # 列表，元素为所有的必填字段
        dict_keys = list(dict_1.keys())
        for i in dict_keys:
            para_list.append(dict_1[i])
        for item in itertools.product(*para_list):
            pai_list.append(item)
        print('必填字段列表dict_keys', dict_keys)
        print('必填字段可选值的列表para_list', para_list)
        print('必填字段可选值排列组合', len(pai_list), pai_list)
        dict_list = []
        for zuhe in pai_list:
            bitian = {}
            for key_index in range(len(dict_keys)):
                bitian[dict_keys[key_index]] = zuhe[key_index]
            dict_list.append(bitian)
        print('必填字段组合总数', len(dict_list))
        print('必填字段组合dict_list', dict_list)
        return dict_list

    def zuhe_data(self, bi_list, fei_list):
        '''
        必填字段排列组合list和非必填字段排列组合list再排列组合
        :param bi_list: 必填字段排列组合list
        :param fei_list: 非必填字段排列组合list
        :return:
        '''
        zuhe_list = []
        for bi in bi_list:
            if len(fei_list) != 0:
                for fei in fei_list:
                    zuhe_dict = {**bi, **fei}
                    zuhe_list.append(zuhe_dict)
            else:
                zuhe_list = bi_list
        print('最终组合序列总数', len(zuhe_list))
        print('最终组合序列，zuhe_list', zuhe_list)
        return zuhe_list

    def paixu(self, arrPara):
        '''
        排序组合接口
        :param arrPara: 参数列表，如
            [
                {'paraName': 'workOrderId', 'type': 'String', 'isNone': 1, 'value': [510000040, 12345]},
                {'paraName': 'file_path', 'type': 'Int', 'isNone': 0, 'value': ''},
            ]
            paraName:参数名
            type：参数类型（非必填）
            isNone:是否必填，0非，1必
            value:必填参数则为列表，非必填则为字符串、数字或其他数据类型
        :return: 所有的参数组合list
        '''
        dict_1, dict_0, list_0 = self.dataInfo(arrPara)
        feiData = self.feiData(list_0, dict_0)
        biData = self.biData(dict_1)
        return self.zuhe_data(biData, feiData)

    def creatPy(self, paixuList, path, keyword):
        '''
        根据参数的所有组合，生成对应的yml文件
        在已经存在test_case.yml的情况下，根据查找关键字，替换yaml文件的参数，生成多个新的test_casen.yml文件，此时只需要修改检查点就好
        :param paixuList: paixuList为paixu()方法的return值
        :param path: 文件的路径
        :param keyword: 查找的关键字
        :return:
        '''
        index = 0
        with open(path, 'r', encoding='utf-8') as f:
            lines = f.readlines()
        for l in lines:
            if l.strip() == keyword + ':':
                # 记录当前的index
                index = lines.index(l)
        for paixu in paixuList:
            # # 第一种参数组合和模版文件重复
            # if paixuList.index(paixu) == 0:
            #     continue

            for i in range(index + 1, index + 1 + len(paixu)):
                new_key = list(paixu.keys())[i - index - 1]
                # print('当前key', new_key)
                # print(lines[i].split(new_key+':'))
                # print(str(paixu[new_key])+',\n')
                # 根据当前key:拆分，生成一个list，对list[-1]判断是否有单引号或者双引号，再进行替换
                line_split = lines[i].split(new_key + ':')
                if line_split[-1] != '':
                    # /n被视作为一个字符，所以倒数第二个应该是-2
                    if line_split[-1][-2] == '"' or line_split[-1][-2] == "'":
                        line_split[-1] = '"' + str(paixu[list(paixu.keys())[i - index - 1]]) + '"\n'
                    else:
                        line_split[-1] = str(paixu[new_key]) + '\n'
                else:
                    print('模版文件当前key', new_key, '值为空')
                new_str = line_split[0] + new_key + ': ' + line_split[-1]

                lines[i] = new_str
            # print('文件名', str(paixuList.index(paixu)))
            with open(path.split('.yml')[0] + str(paixuList.index(paixu)) + '.yml', 'w', encoding='utf-8') as f:
                f.writelines(lines)
        # 生成的所有的文件其中有一个和模版文件是重复的需要把模版文件删除
        # os.remove(path)

    def extendContent(self, paixuList, path, keyword):
        '''
        根据参数组合在模版文件里面添加teststeps的内容。其实是会有一次重复的因为无法判断第一次的参数的组合形式。重复不会影响用例，可忽略
        :param paixuList: paixuList为paixu()方法的return值
        :param path: 文件的路径
        :param keyword: 查找的关键字
        :return:
        '''

        with open(path, 'r', encoding='utf-8') as f:
            lines = f.readlines()
        for l in lines:
            if l.strip() == 'teststeps' + ':':
                # 记录'teststeps'所在行的index
                teststeps_index = lines.index(l)
            if l.strip() == keyword + ':':
                # 记录keyword所在行的index
                keyword_index = lines.index(l)

        # 得到teststeps的内容，改变里面的参数然后扩展到list后面
        new_list = lines[teststeps_index + 1:]
        index = keyword_index - teststeps_index
        for paixu in paixuList:
            content = new_list.copy()
            # 给test name加一个序号做区分,需要考虑引号的问题
            if '"' in content[0]:
                content[0] = str(content[0]).strip('\n').strip('"') + str(paixuList.index(paixu)) + '"\n'
            elif "'" in content[0]:
                content[0] = str(content[0]).strip('\n').strip("'") + str(paixuList.index(paixu)) + "'\n"
            else:
                content[0] = str(content[0]).strip('\n') + str(paixuList.index(paixu)) + '\n'
            paixu_keys = list(paixu.keys())
            for i in range(index, index + len(paixu)):
                for key in paixu_keys:
                    # 遍历paixu_keys当key和对应行的字段匹配时才作为new_key
                    if key in new_list[i]:
                        new_key = key
                        break
                    else:
                        continue

                # 根据当前key:拆分，生成一个list，对list[-1]判断是否有单引号或者双引号，再进行替换
                line_split = content[i].split(new_key + ':')
                # print('line_split[-1]', line_split[-1])
                if line_split[-1] != '':
                    # /n被视作为一个字符，所以倒数第二个应该是-2
                    if str(line_split[-1])[-2] == '"' or str(line_split[-1])[-2] == "'":
                        line_split[-1] = '"' + str(paixu[list(paixu.keys())[i - index]]) + '"\n'
                    else:
                        line_split[-1] = str(paixu[new_key]) + '\n'
                else:
                    print('模版文件当前key', new_key, '值为空')
                new_str = line_split[0] + new_key + ': ' + line_split[-1]

                content[i] = new_str
            lines.extend(['\n'])
            lines.extend(content)
        with open(path, 'w', encoding='utf-8') as f:
            for i in lines:
                f.write(i)
        print(lines)

    def zuhe_main(self, list_data, fileName, keyword, isCreat=0):
        '''

        :param list_data: 参数列表
        :param fileName: 模版文件的路径
        :param keyword: 关键字
        :param isCreat: 0,不新生成yml文件；1，生成新的yml文件
        :return:
        '''
        paixuList = self.paixu(list_data)
        if isCreat == 1:
            # 多个参数组合生成多个yml文件
            self.creatPy(paixuList, fileName, keyword)
        else:
            # 多个参数组合全部扩展到模版yml文件里面
            self.extendContent(paixuList, fileName, keyword)


if __name__ == '__main__':
    list_data = [
        {'paraName': 'isNeedOcrImage', 'type': 'String', 'notNone': 0, 'value': 1},
        {'paraName': 'isNeedOcrText', 'type': 'Int', 'notNone': 0, 'value': 1},
        {'paraName': 'isNeedVideo', 'type': 'Object', 'notNone': 0, 'value': 1},
        {'paraName': 'personCode', 'type': 'Boolean', 'notNone': 1, 'value': ['VTIDU']},
    ]

    # paixuList = ZuhePara().paixu(list_data)
    # 多个参数组合生成多个yml文件
    # ZuhePara().creatPy(paixuList, 'testCp.yml', 'json')

    # 多个参数组合全部扩展到模版yml文件里面
    # ZuhePara().zuhe_main(list_data, 'testCp.yml', 'json')

    list_data1 = [
        {'paraName': 'phone', 'type': 'String', 'notNone': 1, 'value': [18210565620, 18210565621, 18210565622]},
        {'paraName': 'password', 'type': 'Int', 'notNone': 1, 'value': ['qwe123']},
    ]
    # ZuhePara().zuhe_main(list_data1, 'tonglu.yml', 'data')

    list_data2 = [
        {'paraName': 'pageSize', 'type': 'String', 'notNone': 0, 'value': 10},
        {'paraName': 'pageNo', 'type': 'Int', 'notNone': 0, 'value': 1},
        {'paraName': 'queryValue', 'type': 'String', 'notNone': 0, 'value': 414499},
        {'paraName': 'type', 'type': 'Int', 'notNone': 1, 'value': [0, 1, 2, 3, 4]},
        {'paraName': 'companyId', 'type': 'String', 'notNone': 1, 'value': [5012552]},
        {'paraName': 'agencyId', 'type': 'Int', 'notNone': 0, 'value': 1},
    ]
    ZuhePara().zuhe_main(list_data2, 'test.yml', 'params')
